package com.bang.daybreak.common.util;

import com.bang.daybreak.common.annotation.Desensitized;
import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;

/**
 * <p>
 * 敏感字段脱敏工具类。需要在实体类中实现toString方法。
 * </p>
 *
 * @version 1.0
 * @author : wdj
 * @since : 2019/7/28 0028 上午 10:00
 */
public class DesensitizedToStringBuilder extends ReflectionToStringBuilder {
    public DesensitizedToStringBuilder(Object object) {
        super(object);
    }

    public DesensitizedToStringBuilder(Object object, ToStringStyle style) {
        super(object, style);
    }

    @Override
    protected void appendFieldsIn(Class clazz) {

        // 反射读取字段
        if (clazz.isArray()) {
            this.reflectionAppendArray(this.getObject());
        } else {
            Field[] fields = clazz.getDeclaredFields();
            AccessibleObject.setAccessible(fields, true);

            for (int i = 0; i < fields.length; ++i) {
                Field field = fields[i];
                String fieldName = field.getName();
                if (this.accept(field)) {
                    try {
                        Object fieldValue = this.getValue(field);
                        if (fieldValue != null) {
                            // 获取注解信息
                            Desensitized anno = (Desensitized) field.getAnnotation(Desensitized.class);
                            if (anno != null && field.getType() == String.class) {
                                String strFieldVal = (String) fieldValue;
                                int length = strFieldVal.length();

                                // 如果设置按照特殊字符规则来脱敏，优先级高于下标形式。
                                // 首先判断字符串是否包含该特殊字符
                                int suffixNonSensitiveLen = anno.suffixNonSensitiveLen();
                                int index = StringUtil.indexOf(strFieldVal, anno.character());
                                if (index > 1) {
                                    suffixNonSensitiveLen = strFieldVal.length() - index;
                                }
                                int totalNoMaskLen = anno.prefixNonSensitiveLen() + suffixNonSensitiveLen;
                                // totalNoMaskLen == 0 全部加密
                                if (totalNoMaskLen == 0) {
                                    fieldValue = this.fillMask(anno.rule(), length);
                                }

                                // 按照规则加密.
                                if (totalNoMaskLen < length) {
                                    StringBuilder sb = new StringBuilder();

                                    for (int j = 0; j < strFieldVal.length(); ++j) {
                                        if (j < anno.prefixNonSensitiveLen()) {
                                            sb.append(strFieldVal.charAt(j));
                                        } else if (j > strFieldVal.length() - suffixNonSensitiveLen - 1) {
                                            sb.append(strFieldVal.charAt(j));
                                        } else {
                                            sb.append(anno.rule());
                                        }
                                    }

                                    fieldValue = sb.toString();
                                }
                            }

                            this.append(fieldName, fieldValue);
                        }
                    } catch (IllegalAccessException var13) {
                        throw new InternalError("Unexpected IllegalAccessException: " + var13.getMessage());
                    }
                }
            }

        }
    }

    private String fillMask(String rule, int length) {
        StringBuilder sb = new StringBuilder();

        for (int i = 0; i < length; ++i) {
            sb.append(rule);
        }

        return sb.toString();
    }
}
